import sys, time
import socket,fcntl,struct
import subprocess
import argparse, re
import NLAgent
import NLAgentClient
import NLAgentServer
import socketserver as SocketServer
from multiprocessing import Process

# The names (linux) or ips (darwin) of ip aliases we brought up
# and therefore should bring down when we're done.
aliases_brought_up = []


parser = argparse.ArgumentParser(parents=[NLAgent.parser])
parser.add_argument('--interface', action="store", dest='iface', required=True)
parser.add_argument('--divide', action="store", dest='divide_file', required=True)
parser.add_argument('--sources', action="store", dest='srcs', required=True)
parser.add_argument('--group', action="store", dest='my_group', required=True)
parser.add_argument('--setup', action="store_true", default=False, help="Bring up (and leave up) appropriate interfaces and do nothing else")

if sys.platform.startswith('freebsd'):
  pass
elif sys.platform.startswith('darwin'):
  pass
elif sys.platform.startswith('linux'):
  pass
else:
  pass

src_list = []

class SyncHandler(SocketServer.BaseRequestHandler):

    def handle(self):
      #self.data = self.request.recv(1024).strip()
      clientip = self.client_address[0]
      (hostname, aliaslist, ipaddrlist) = socket.gethostbyaddr(clientip)
      host = aliaslist[len(aliaslist)-1]
      if host in src_list:
        print("Got sync from host ", host)
        src_list.remove(host)
        if (len(src_list) == 0):
          print("End of the list")
       #self.request.sendall(self.data.upper())



def get_current_ips():
  if sys.platform.startswith('linux'):
    ifconfig = (subprocess.getoutput('/sbin/ifconfig'))
  elif sys.platform.startswith('darwin'):
    ifconfig = (subprocess.getoutput('/sbin/ifconfig'))
  else:
    return  None  
  currentips = re.findall(r'(?:[\d]{1,3})\.(?:[\d]{1,3})\.(?:[\d]{1,3})\.(?:[\d]{1,3})', ifconfig)
  return currentips

def bring_up_ip(ip, iface):
  print("Bringing up ", ip , "on ", iface)
  if sys.platform.startswith('linux'):
    # We need to determine what number alias we want.
    # So we first find what alias names are being used.
    ifconfig_output = (subprocess.getoutput('/sbin/ifconfig'))
    regex = '(' + iface +'\:)([\w]+)'
    currentaliases = re.findall(regex,ifconfig_output)
    anames = []
    for a in currentaliases:
      anames.append(a[1])
    i=0
    while str(i) in anames:
      i += 1
      
    alias = iface + ':' + str(i)
    subprocess.call(["/usr/bin/sudo", "/sbin/ifconfig", alias, ip, "netmask", "255.255.255.0", "up"])
    aliases_brought_up.append(alias)
    
  elif sys.platform.startswith('darwin'):
    subprocess.call(["/usr/bin/sudo", "/sbin/ifconfig", iface, "alias", ip, "255.255.255.0"])
    aliases_brought_up.append(ip)
    print(ip)
  else:
    print("Running on an unsupported platform.")

def bring_down_ip(name, iface):
  if sys.platform.startswith('linux'):
    subprocess.call(["/usr/bin/sudo", "/sbin/ifconfig", name, "down"])
  elif sys.platform.startswith('darwin'):
    subprocess.call(["/usr/bin/sudo", "/sbin/ifconfig", iface, "-alias", name])

def clean_up():
  for name in aliases_brought_up:
    print("Bringing down ", name)
    bring_down_ip(name, args.iface)

def start_sync_server():
  host = ''    
  port = 10001
  addr = (host, port)
  bufsize = 4096    
  server = SocketServer.TCPServer(addr, SyncHandler)
  server.allow_reuse_address= True;
  while (len(src_list) > 0):
    server.handle_request()
  print("End of sync server")

def wait_for_sync_server(server):
  print("Waiting for sync server", server)
  host, port = server, 10001
  sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  try:
    # Connect to server and send data
    sock.connect((host, port))
    print("Connected successfully")
  finally:
    sock.close()

  
if __name__ == "__main__":
  args = parser.parse_args()
  print(args)
  current = get_current_ips()
  
  f = open(args.srcs, 'r')
  (hostname, sep, rest) = socket.gethostname().partition(".")
  first = -1
  i = 0
  for name in f:
    if (i == 0):
        if (name.strip() == hostname.strip()):
          first = 0
        else:
          first = name.strip()
    else:
      src_list.append(name.strip())
    i = i+1

  if args.setup:
    print("Bringing up interfaces aliases and quitting.")
  
  ip_list = [];
  if args.divide_file != None:
    ip_list = NLAgent.ParseIPList(args.divide_file, args.my_group)
    print("IP list has ",len(ip_list), " addresses");

  p = None
  try: 
    if args.setup:
      for ip in ip_list:
        if ip not in current:        
          print("Bring up ",ip);
          bring_up_ip(ip, args.iface)
          current.append(ip)
    else:
      print("Starting server")
      NLAgentServer.init_servers(args.filename, args.master_start_time, ip_list, time.time())
      if (first == 0):
        print("I am first")
        start_sync_server()
      else:
        wait_for_sync_server(first)
      NLAgentServer.run(args.filename, args.master_start_time, ip_list, time.time())
      #NLAgentClient.run_clients(args.filename, args.master_start_time, ip_list)
      pass
  
  except KeyboardInterrupt:
    clean_up()
    exit(1)
  
  if not args.setup:
    clean_up()
    
    
